# -*- coding: utf-8 -*-
#
#  util.py -- Misc utility functions
#  Thomas Perl <thp@perli.net> 2007-08-04
#

"""
Miscellaneous helper functions

"""

import os.path, re

def get_first_line( s):
    """
    Returns only the first line of a string, stripped so
    that it doesn't have whitespace before or after.
    """
    return s.strip().split('\n')[0].strip()


def normalize_feed_url(url):
    """
    Converts any URL to http:// so that it can be 
    used with "wget". If the URL cannot be converted (invalid
    or unknown scheme), "None" is returned.

    This will also normalize feed:// and itpc:// to http://

    If no URL scheme is defined (e.g. "curry.com"), we will
    simply assume the user intends to add a http:// feed.
    """

    if not url or len(url) < 8:
        return None

    if not '://' in url:
        return 'http://' + url

    if url.startswith('http://'):
        return url

    if url.startswith('feed://') or url.startswith('itpc://'):
        return 'http://' + url[7:]

    return None


def file_type_by_extension(extension):
    """
    Tries to guess the file type by looking up the filename 
    extension from a table of known file types. Will return 
    the type as string ("audio" or "video") or
    None if the file type cannot be determined.
    """
    types = {
        'audio': [ 'mp3', 'ogg'], #, 'wav', 'wma', 'aac', 'm4a' ],
        #'video': [ 'mp4', 'avi', 'mpg', 'mpeg', 'm4v', 'mov', 'divx', 'flv', 'wmv', '3gp' ],
    }

    if extension == '':
        return None

    if extension[0] == '.':
        extension = extension[1:]

    extension = extension.lower()

    for type in types:
        if extension in types[type]:
            return type
    
    return None


def filename_from_url(url):
    """
    Extracts the filename and (lowercase) extension (with dot)
    from a URL, e.g. http://server.com/file.MP3?download=yes
    will result in the string ("file", ".mp3") being returned.

    This function will also try to best-guess the "real" 
    extension for a media file (audio, video) by
    trying to match an extension to these types and recurses
    into the query string to find better matches, if the 
    original extension does not resolve to a known type.

    http://my.net/redirect.php?my.net/file.ogg => ("file", ".ogg")
    http://server/get.jsp?file=/episode0815.MOV => ("episode0815", ".mov")
    http://s/redirect.mp4?http://serv2/test.mp4 => ("test", ".mp4")
    """
    import urlparse, urllib2

    url = url.replace('%3A', ':').replace('%2F', '/')

    (scheme, netloc, path, para, query, fragid) = urlparse.urlparse(url)
    (filename, extension) = os.path.splitext(os.path.basename(urllib2.unquote(path)))

    if file_type_by_extension(extension) is not None and query.find(scheme + '://') == -1:
        # We have found a valid extension and the query string doesn't look like an URL
        return (filename, extension.lower())

    # If the query string looks like a possible URL, try that first
    if len(query.strip()) > 0 and query.find('/') != -1:
        query_url = '://'.join((scheme, urllib2.unquote(query)))
        (query_filename, query_extension) = filename_from_url(query_url)

        if file_type_by_extension(query_extension) is not None:
            return os.path.splitext(os.path.basename(query_url))

    # No exact match found, simply returns the original filename & extension
    return (filename, extension.lower())


def remove_html_tags(html):
    """
    Remove HTML tags from a string and replace numeric and
    named entities with the corresponding character, so the 
    HTML text can be displayed in a simple text view.
    """
    from htmlentitydefs import entitydefs

    # If we would want more speed, we could make these global
    re_strip_tags = re.compile('<[^>]*>')
    re_unicode_entities = re.compile('&#(\d{2,4});')
    re_html_entities = re.compile('&(.{2,8});')
    re_newline_tags = re.compile('(<br[^>]*>|<[/]?ul[^>]*>|</li>)', re.I)
    re_listing_tags = re.compile('<li[^>]*>', re.I)

    result = html
    
    # Convert common HTML elements to their text equivalent
    result = re_newline_tags.sub('\n', result)
    result = re_listing_tags.sub('\n * ', result)
    result = re.sub('<[Pp]>', '\n\n', result)

    # Remove all HTML/XML tags from the string
    result = re_strip_tags.sub('', result)

    # Remove URLs (Podboy Hack)
    re_url = re.compile('(http://|https://){0,1}[A-Za-z0-9][A-Za-z0-9\-\.]+[A-Za-z0-9]\.[A-Za-z]{2,}[\43-\176]*')
    result = re.sub(re_url, '', result)

    # Convert numeric XML entities to their unicode character
    result = re_unicode_entities.sub(lambda x: unichr(int(x.group(1))), result)

    # Convert named HTML entities to their unicode character
    result = re_html_entities.sub(lambda x: unicode(entitydefs.get(x.group(1),''), 'iso-8859-1'), result)
    
    # Convert more than two newlines to two newlines
    result = re.sub('([\r\n]{2})([\r\n])+', '\\1', result)

    # (Podboy Hack)
    result = result.replace('\r', '').replace('\n', '<br>')

    return result.strip()


def format_filesize(bytesize, use_si_units = False, digits = 2):
    """
    Formats the given size in bytes to be human-readable, 

    Returns a localized "(unknown)" string when the bytesize
    has a negative value.
    """
    si_units = (
        ('kB', 10**3),
        ('MB', 10**6),
        ('GB', 10**9),
    )

    binary_units = (
        ('KiB', 2**10),
        ('MiB', 2**20),
        ('GiB', 2**30),
    )

    try:
        bytesize = float(bytesize)
    except:
        return 'Unknown'

    if bytesize < 0:
        return 'Unknown'

    if use_si_units:
        units = si_units
    else:
        units = binary_units

    (used_unit, used_value) = ('B', bytesize)

    for (unit, value) in units:
        if bytesize >= value:
            used_value = bytesize / float(value)
            used_unit = unit

    return ('%.' + str(digits) + 'f %s') % (used_value, used_unit)


def init_bluetooth():
    # Useful commands for some devices:
    #     hciconfig hci0 lm accept,master
    #     hciconfig hci0 lp hold,sniff,park
    # any of them are necessary for my Sony Erricson HBH-DS200
    # but my Motorola S9 requires the second

    import subprocess
    FNULL = open('/dev/null', 'w')
    #subprocess.Popen(
    #    'kill -9 `pidof bluetoothd`; /usr/sbin/bluetoothd --udev',
    #    shell = True, stdout = FNULL, stderr = FNULL)
    subprocess.Popen(
        'hciconfig hci0 lm accept,master; hciconfig hci0 lp hold,sniff,park',
        shell = True, stdout = FNULL, stderr = FNULL)
